package simplytypedinference

class Context[A <: Binding](bindings: List[(String,A)]) {
 private val bins : List[(String,A)] = bindings
 def apply(i: Int) : A         = bins(i)._2
 def + (n: String, b: A) = new Context[A]( (n,b):: bins)
 def getIndexOfName(n: String) :Int = getIndexOfName(n, bins)
 private def getIndexOfName(n: String,bins: List[(String,A)]) : Int = {
   val index = bins.map {case (n, _) => n} indexOf(n)
   if(index == -1) throw new Exception(n +" is unbound variable") else index
 }
   /*bins match {
   case Nil => throw new Exception(n +" is unbound variable")
   case (s,_)::bs => if (s equals n ) 0
                     else 1 + getIndexOfName(n,bs)
 }*/
 def isNameBound(n: String): Boolean =  bins exists { case (s, b)  => (s == n) }
 /*{
   Nil != (bins.filter ( Function.tupled( (s:String,b:A)  => (s == n) )))
 }*/
 
 override def toString = bins.toString
}



abstract class Binding
case class NameBinding(name: String) extends Binding
case class VarBinding(ltype: LType) extends Binding
